using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Linq.Expressions;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Sio.Cms.Lib;
using Sio.Cms.Lib.Models.Cms;
using Sio.Cms.Lib.Services;
using Sio.Cms.Web.Models;
using Sio.Domain.Core.ViewModels;
using Sio.Identity.Models;
using static Sio.Cms.Lib.SioEnums;

namespace Sio.Cms.Web.Controllers
{
    public class HomeController : BaseController
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly IApiDescriptionGroupCollectionProvider _apiExplorer;
        public HomeController(IHostingEnvironment env,
            IMemoryCache memoryCache,
             UserManager<ApplicationUser> userManager,
             IApiDescriptionGroupCollectionProvider apiExplorer,
            IHttpContextAccessor accessor
            ) : base(env, memoryCache, accessor)
        {
            this._userManager = userManager;
            _apiExplorer = apiExplorer;
        }

        #region Routes

        [Route("")]
        [Route("{culture}")]
        [Route("{culture}/{alias}")]
        public async System.Threading.Tasks.Task<IActionResult> Alias(string culture,
            string alias, int pageIndex, int pageSize = 10)
        {
            string seoName = Request.Query["alias"];
            seoName = seoName ?? alias;
            if (_forbidden)
            {
                return Redirect($"/error/403");
            }
            if (SioService.GetConfig<bool>("IsMaintenance"))
            {
                return Redirect($"/maintenance");
            }

            if (SioService.GetConfig<bool>("IsInit"))
            {
                //Go to landing page
                return await AliasAsync(seoName);
            }
            else
            {
                if (string.IsNullOrEmpty(SioService.GetConnectionString(SioConstants.CONST_CMS_CONNECTION)))
                {
                    return Redirect("Init");
                }
                else
                {
                    return Redirect($"/init/step2");
                }
            }
        }

        [Route("{culture}/page")]
        [Route("{culture}/page/{seoName}")]
        public async System.Threading.Tasks.Task<IActionResult> Page(
            string culture, string seoName)
        {
            if (_forbidden)
            {
                return Redirect($"/error/403");
            }
            if (SioService.GetConfig<bool>("IsMaintenance"))
            {
                return Redirect($"/maintenance");
            }

            if (SioService.GetConfig<bool>("IsInit"))
            {
                //Go to landing page
                return await PageAsync(seoName);
            }
            else
            {
                if (string.IsNullOrEmpty(SioService.GetConnectionString(SioConstants.CONST_CMS_CONNECTION)))
                {
                    return Redirect("Init");
                }
                else
                {
                    return Redirect($"/init/step2");
                }
            }
        }

        [Route("{culture}/tag/{tagName}")]
        public async System.Threading.Tasks.Task<IActionResult> Tag(string culture, string tagName)
        {
            if (_forbidden)
            {
                return Redirect($"/error/403");
            }
            return await TagAsync(tagName);
        }

        [Route("{culture}/search/{keyword}")]
        public async System.Threading.Tasks.Task<IActionResult> Search(string culture, string keyword)
        {
            if (_forbidden)
            {
                return Redirect($"/error/403");
            }
            return await SearchAsync(keyword);
        }

        [Route("article/{id}/{seoName}")]
        [Route("{culture}/article/{id}/{seoName}")]
        public async System.Threading.Tasks.Task<IActionResult> Article(int id, string culture, string seoName)
        {
            if (_forbidden)
            {
                return Redirect($"/error/403");
            }
            return await ArticleViewAsync(id, seoName);
        }

        [Route("product/{seoName}")]
        [Route("{culture}/product/{seoName}")]
        public async System.Threading.Tasks.Task<IActionResult> Product(string culture, string seoName)
        {
            if (_forbidden)
            {
                return Redirect($"/error/403");
            }
            return await ProductViewAsync(seoName);
        }

        [HttpGet]
        [Route("portal")]
        [Route("admin")]
        [Route("portal/{pageName}")]
        [Route("portal/{pageName}/{type}")]
        [Route("portal/{pageName}/{type}/{param}")]
        [Route("portal/{pageName}/{type}/{param}/{param1}")]
        [Route("portal/{pageName}/{type}/{param}/{param1}/{param2}")]
        [Route("portal/{pageName}/{type}/{param}/{param1}/{param2}/{param3}")]
        [Route("portal/{pageName}/{type}/{param}/{param1}/{param2}/{param3}/{param4}")]
        public IActionResult Portal()
        {
            if (_forbiddenPortal)
            {
                return Redirect($"/error/403");
            }
            return View();
        }

        [HttpGet]
        [Route("init")]
        [Route("init/{page}")]
        public IActionResult Init(string page)
        {
            if (_forbidden)
            {
                return Redirect($"/error/403");
            }
            if (string.IsNullOrEmpty(page) && SioService.GetConfig<bool>("IsInit"))
            {
                return Redirect($"/init/login");
            }
            else
            {
                return View();
            }

        }

        [HttpGet]
        [Route("error/{page}")]
        public async System.Threading.Tasks.Task<IActionResult> PageError(string page = "404")
        {
            return await PageAsync(page);
        }

        [HttpGet]
        [Route("maintenance")]
        public async System.Threading.Tasks.Task<IActionResult> Maintenance()
        {
            return await PageAsync("Maintenance");
        }

        #endregion
        #region Helper

        async System.Threading.Tasks.Task<IActionResult> AliasAsync(string seoName)
        {
            // Home Page
            int.TryParse(Request.Query["pageSize"], out int pageSize);
            int.TryParse(Request.Query["pageIndex"], out int pageIndex);
            var getAlias = new RepositoryResponse<Lib.ViewModels.SioUrlAliases.UpdateViewModel>();
            var cacheKey = $"alias_{_culture}_{seoName}_{pageSize}_{pageIndex}";

            var data = _memoryCache.Get<Lib.ViewModels.SioUrlAliases.UpdateViewModel>(cacheKey);
            if (data != null && SioService.GetConfig<bool>("IsCache"))
            {
                getAlias.IsSucceed = true;
                getAlias.Data = data;
            }
            else
            {
                Expression<Func<SioUrlAlias, bool>> predicate;

                predicate = p =>
                p.Alias == seoName
                && p.Status == (int)SioContentStatus.Published && p.Specificulture == _culture;

                getAlias = await Lib.ViewModels.SioUrlAliases.UpdateViewModel.Repository.GetSingleModelAsync(predicate);

                _memoryCache.Set(cacheKey, getAlias.Data);
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }
            }

            if (getAlias.IsSucceed)// && getPage.Data.View != null
            {
                switch (getAlias.Data.Type)
                {
                    case UrlAliasType.Page:
                        return await PageAsync(int.Parse(getAlias.Data.SourceId));
                    case UrlAliasType.Article:
                        return await ArticleViewAsync(int.Parse(getAlias.Data.SourceId));
                    case UrlAliasType.Product:
                    case UrlAliasType.Module:
                    case UrlAliasType.ModuleData:
                    default:
                        return await PageError();
                }
            }
            else
            {
                return await PageAsync(seoName);
            }
        }

        async System.Threading.Tasks.Task<IActionResult> PageAsync(string seoName)
        {

            // Home Page
            int.TryParse(Request.Query["pageSize"], out int pageSize);
            int.TryParse(Request.Query["pageIndex"], out int pageIndex);
            var getPage = new RepositoryResponse<Lib.ViewModels.SioPages.ReadMvcViewModel>();
            var cacheKey = $"page_{_culture}_{seoName}_{pageSize}_{pageIndex}";

            var data = _memoryCache.Get<Lib.ViewModels.SioPages.ReadMvcViewModel>(cacheKey);
            if (data != null && SioService.GetConfig<bool>("IsCache"))
            {
                getPage.IsSucceed = true;
                getPage.Data = data;
            }
            else
            {
                Expression<Func<SioPage, bool>> predicate;
                if (string.IsNullOrEmpty(seoName))
                {
                    predicate = p =>
                    p.Type == (int)SioPageType.Home
                    && p.Status == (int)SioContentStatus.Published && p.Specificulture == _culture;
                }
                else
                {
                    predicate = p =>
                    p.SeoName == seoName
                    && p.Status == (int)SioContentStatus.Published && p.Specificulture == _culture;
                }

                getPage = await Lib.ViewModels.SioPages.ReadMvcViewModel.Repository.GetSingleModelAsync(predicate);
                if (getPage.Data != null)
                {
                    getPage.Data.LoadData(pageIndex: pageIndex, pageSize: pageSize);
                }
                _memoryCache.Set(cacheKey, getPage.Data);
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }
            }

            if (getPage.IsSucceed)// && getPage.Data.View != null
            {
                GeneratePageDetailsUrls(getPage.Data);
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }
                ViewData["TopPages"] = GetCategory(CatePosition.Nav, seoName);
                ViewData["HeaderPages"] = GetCategory(CatePosition.Top, seoName);
                ViewData["FooterPages"] = GetCategory(CatePosition.Footer, seoName);
                ViewData["LeftPages"] = GetCategory(CatePosition.Left, seoName);

                ViewData["Title"] = getPage.Data.SeoTitle;
                ViewData["Description"] = getPage.Data.SeoDescription;
                ViewData["Keywords"] = getPage.Data.SeoKeywords;
                ViewData["Image"] = getPage.Data.ImageUrl;
                ViewData["PageClass"] = getPage.Data.CssClass;
                getPage.LastUpdateConfiguration = SioService.GetConfig<DateTime?>("LastUpdateConfiguration");
                return View(getPage.Data);
            }
            else
            {
                return Redirect($"/error/404");
            }
        }
        async System.Threading.Tasks.Task<IActionResult> PageAsync(int pageId)
        {

            // Home Page
            int.TryParse(Request.Query["pageSize"], out int pageSize);
            int.TryParse(Request.Query["pageIndex"], out int pageIndex);
            var getPage = new RepositoryResponse<Lib.ViewModels.SioPages.ReadMvcViewModel>();
            var cacheKey = $"page_{_culture}_{pageId}_{pageSize}_{pageIndex}";

            var data = _memoryCache.Get<Lib.ViewModels.SioPages.ReadMvcViewModel>(cacheKey);
            if (data != null && SioService.GetConfig<bool>("IsCache"))
            {
                getPage.IsSucceed = true;
                getPage.Data = data;

            }
            else
            {
                Expression<Func<SioPage, bool>> predicate;

                predicate = p =>
                p.Id == pageId
                && p.Status == (int)SioContentStatus.Published && p.Specificulture == _culture;

                getPage = await Lib.ViewModels.SioPages.ReadMvcViewModel.Repository.GetSingleModelAsync(predicate);
                if (getPage.Data != null)
                {
                    getPage.Data.LoadData(pageIndex: pageIndex, pageSize: pageSize);
                    getPage.Data.DetailsUrl = GenerateDetailsUrl("Page", new { seoName = getPage.Data.SeoName });
                }

                _memoryCache.Set(cacheKey, getPage.Data);
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }
            }

            if (getPage.IsSucceed)// && getPage.Data.View != null
            {
                ViewData["TopPages"] = GetCategory(CatePosition.Nav, getPage.Data.SeoName);
                ViewData["HeaderPages"] = GetCategory(CatePosition.Top, getPage.Data.SeoName);
                ViewData["FooterPages"] = GetCategory(CatePosition.Footer, getPage.Data.SeoName);
                ViewData["LeftPages"] = GetCategory(CatePosition.Left, getPage.Data.SeoName);

                ViewData["Title"] = getPage.Data.SeoTitle;
                ViewData["Description"] = getPage.Data.SeoDescription;
                ViewData["Keywords"] = getPage.Data.SeoKeywords;
                ViewData["Image"] = getPage.Data.ImageUrl;
                ViewData["PageClass"] = getPage.Data.CssClass;

                GeneratePageDetailsUrls(getPage.Data);
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }

                getPage.LastUpdateConfiguration = SioService.GetConfig<DateTime?>("LastUpdateConfiguration");
                return View(getPage.Data);
            }
            else
            {
                return Redirect($"/error/404");
            }
        }

        async System.Threading.Tasks.Task<IActionResult> TagAsync(string tagName)
        {
            string seoName = "tag";
            ViewData["TopPages"] = GetCategory(CatePosition.Nav, seoName);
            ViewData["HeaderPages"] = GetCategory(CatePosition.Top, seoName);
            ViewData["FooterPages"] = GetCategory(CatePosition.Footer, seoName);
            ViewData["LeftPages"] = GetCategory(CatePosition.Left, seoName);
            ViewData["TagName"] = tagName;

            int? pageSize = SioService.GetConfig<int?>("TagPageSize");
            string orderBy = SioService.GetConfig<string>("OrderBy");
            int orderDirection = SioService.GetConfig<int>("OrderDirection");
            int.TryParse(Request.Query["pageIndex"], out int pageIndex);
            var getPage = new RepositoryResponse<Lib.ViewModels.SioPages.ReadMvcViewModel>();
            var cacheKey = $"tag_{_culture}_{tagName}_{pageSize}_{pageIndex}";
            var data = _memoryCache.Get<Lib.ViewModels.SioPages.ReadMvcViewModel>(cacheKey);
            if (data != null && SioService.GetConfig<bool>("IsCache"))
            {
                getPage.IsSucceed = true;
                getPage.Data = data;
            }
            else
            {
                Expression<Func<SioPage, bool>> predicate;

                predicate = p =>
                p.SeoName == "tag"
                && p.Status == (int)SioContentStatus.Published && p.Specificulture == _culture;

                getPage = await Lib.ViewModels.SioPages.ReadMvcViewModel.Repository.GetSingleModelAsync(predicate);
                if (getPage.Data != null)
                {
                    getPage.Data.LoadDataByTag(tagName, orderBy, orderDirection, pageIndex: pageIndex, pageSize: pageSize);
                }
                _memoryCache.Set(cacheKey, getPage.Data);
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }
            }

            if (getPage.IsSucceed)// && getPage.Data.View != null
            {
                GeneratePageDetailsUrls(getPage.Data);
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }
                ViewData["Title"] = getPage.Data.SeoTitle;
                ViewData["Description"] = getPage.Data.SeoDescription;
                ViewData["Keywords"] = getPage.Data.SeoKeywords;
                ViewData["Image"] = getPage.Data.ImageUrl;
                ViewData["PageClass"] = getPage.Data.CssClass;
                getPage.LastUpdateConfiguration = SioService.GetConfig<DateTime?>("LastUpdateConfiguration");
                return View(getPage.Data);
            }
            else
            {
                return Redirect($"/error/404");
            }
        }
        async System.Threading.Tasks.Task<IActionResult> SearchAsync(string keyword)
        {
            string seoName = "search";
            ViewData["TopPages"] = GetCategory(CatePosition.Nav, seoName);
            ViewData["HeaderPages"] = GetCategory(CatePosition.Top, seoName);
            ViewData["FooterPages"] = GetCategory(CatePosition.Footer, seoName);
            ViewData["LeftPages"] = GetCategory(CatePosition.Left, seoName);

            int? pageSize = SioService.GetConfig<int?>("SearchPageSize");
            string orderBy = SioService.GetConfig<string>("OrderBy");
            int orderDirection = SioService.GetConfig<int>("OrderDirection");
            int.TryParse(Request.Query["pageIndex"], out int pageIndex);
            var getPage = new RepositoryResponse<Lib.ViewModels.SioPages.ReadMvcViewModel>();
            var cacheKey = $"search_{_culture}_{keyword}_{pageSize}_{pageIndex}";
            var data = _memoryCache.Get<Lib.ViewModels.SioPages.ReadMvcViewModel>(cacheKey);
            if (data != null && SioService.GetConfig<bool>("IsCache"))
            {
                getPage.IsSucceed = true;
                getPage.Data = data;
            }
            else
            {
                Expression<Func<SioPage, bool>> predicate;

                predicate = p =>
                p.SeoName == "search"
                && p.Status == (int)SioContentStatus.Published && p.Specificulture == _culture;

                getPage = await Lib.ViewModels.SioPages.ReadMvcViewModel.Repository.GetSingleModelAsync(predicate);
                if (getPage.Data != null)
                {
                    getPage.Data.LoadDataByKeyword(keyword, orderBy, orderDirection, pageIndex: pageIndex, pageSize: pageSize);
                }
                _memoryCache.Set(cacheKey, getPage.Data);
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }
            }

            if (getPage.IsSucceed)// && getPage.Data.View != null
            {
                GeneratePageDetailsUrls(getPage.Data);
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }
                ViewData["Title"] = getPage.Data.SeoTitle;
                ViewData["Description"] = getPage.Data.SeoDescription;
                ViewData["Keywords"] = getPage.Data.SeoKeywords;
                ViewData["Image"] = getPage.Data.ImageUrl;
                ViewData["PageClass"] = getPage.Data.CssClass;
                getPage.LastUpdateConfiguration = SioService.GetConfig<DateTime?>("LastUpdateConfiguration");
                return View(getPage.Data);
            }
            else
            {
                return Redirect($"/error/404");
            }
        }

        async System.Threading.Tasks.Task<IActionResult> ArticleViewAsync(int id)
        {

            var getArticle = new RepositoryResponse<Lib.ViewModels.SioArticles.ReadMvcViewModel>();

            var cacheKey = $"article_{_culture}_{id}";

            var data = _memoryCache.Get<Lib.ViewModels.SioArticles.ReadMvcViewModel>(cacheKey);
            if (data != null && SioService.GetConfig<bool>("IsCache"))
            {
                getArticle.IsSucceed = true;
                getArticle.Data = data;
            }
            else
            {
                Expression<Func<SioArticle, bool>> predicate;

                predicate = p =>
                p.Id == id
                && p.Status == (int)SioContentStatus.Published
                && p.Specificulture == _culture;

                getArticle = await Lib.ViewModels.SioArticles.ReadMvcViewModel.Repository.GetSingleModelAsync(predicate);
                if (getArticle.IsSucceed)
                {
                    getArticle.Data.DetailsUrl = GenerateDetailsUrl("Article", new { id = getArticle.Data.Id, seoName = getArticle.Data.SeoName });
                    //Generate details url for related articles
                    if (getArticle.Data.ArticleNavs != null && getArticle.Data.ArticleNavs.Count > 0)
                    {
                        getArticle.Data.ArticleNavs.ForEach(n => n.RelatedArticle.DetailsUrl = GenerateDetailsUrl("Article", new { id = n.RelatedArticle.Id, seoName = n.RelatedArticle.SeoName }));
                    }
                    _memoryCache.Set(cacheKey, getArticle.Data);
                }
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }

            }

            if (getArticle.IsSucceed)
            {
                ViewData["TopPages"] = GetCategory(CatePosition.Nav, getArticle.Data.SeoName);
                ViewData["HeaderPages"] = GetCategory(CatePosition.Top, getArticle.Data.SeoName);
                ViewData["FooterPages"] = GetCategory(CatePosition.Footer, getArticle.Data.SeoName);
                ViewData["LeftPages"] = GetCategory(CatePosition.Left, getArticle.Data.SeoName);

                ViewData["Title"] = getArticle.Data.SeoTitle;
                ViewData["Description"] = getArticle.Data.SeoDescription;
                ViewData["Keywords"] = getArticle.Data.SeoKeywords;
                ViewData["Image"] = getArticle.Data.ImageUrl;
                getArticle.LastUpdateConfiguration = SioService.GetConfig<DateTime?>("LastUpdateConfiguration");
                return View(getArticle.Data);
            }
            else
            {
                return Redirect($"/error/404");
            }
        }
        async System.Threading.Tasks.Task<IActionResult> ArticleViewAsync(int id, string seoName)
        {
            ViewData["TopPages"] = GetCategory(CatePosition.Nav, seoName);
            ViewData["HeaderPages"] = GetCategory(CatePosition.Top, seoName);
            ViewData["FooterPages"] = GetCategory(CatePosition.Footer, seoName);
            ViewData["LeftPages"] = GetCategory(CatePosition.Left, seoName);
            var getArticle = new RepositoryResponse<Lib.ViewModels.SioArticles.ReadMvcViewModel>();

            var cacheKey = $"article_{_culture}_{seoName}";

            var data = _memoryCache.Get<Lib.ViewModels.SioArticles.ReadMvcViewModel>(cacheKey);
            if (data != null && SioService.GetConfig<bool>("IsCache"))
            {
                getArticle.IsSucceed = true;
                getArticle.Data = data;
            }
            else
            {
                Expression<Func<SioArticle, bool>> predicate;
                if (string.IsNullOrEmpty(seoName))
                {
                    predicate = p =>
                    p.Type == (int)SioPageType.Home
                    && p.Status == (int)SioContentStatus.Published && p.Specificulture == _culture;
                }
                else
                {
                    predicate = p =>
                    p.Id == id
                    && p.Status == (int)SioContentStatus.Published
                    && p.Specificulture == _culture;
                }

                getArticle = await Lib.ViewModels.SioArticles.ReadMvcViewModel.Repository.GetSingleModelAsync(predicate);
                if (getArticle.IsSucceed)
                {
                    getArticle.Data.DetailsUrl = GenerateDetailsUrl("Article", new { id = getArticle.Data.Id, seoName = getArticle.Data.SeoName });
                    //Generate details url for related articles
                    if (getArticle.Data.ArticleNavs != null && getArticle.Data.ArticleNavs.Count > 0)
                    {
                        getArticle.Data.ArticleNavs.ForEach(n => n.RelatedArticle.DetailsUrl = GenerateDetailsUrl("Article", new { id = n.RelatedArticle.Id, seoName = n.RelatedArticle.SeoName }));
                    }
                    _memoryCache.Set(cacheKey, getArticle.Data);
                }
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }

            }

            if (getArticle.IsSucceed)
            {
                ViewData["Title"] = getArticle.Data.SeoTitle;
                ViewData["Description"] = getArticle.Data.SeoDescription;
                ViewData["Keywords"] = getArticle.Data.SeoKeywords;
                ViewData["Image"] = getArticle.Data.ImageUrl;
                getArticle.LastUpdateConfiguration = SioService.GetConfig<DateTime?>("LastUpdateConfiguration");
                return View(getArticle.Data);
            }
            else
            {
                return Redirect($"/error/404");
            }
        }

        async System.Threading.Tasks.Task<IActionResult> ProductViewAsync(string seoName)
        {
            ViewData["TopPages"] = GetCategory(CatePosition.Nav, seoName);
            ViewData["HeaderPages"] = GetCategory(CatePosition.Top, seoName);
            ViewData["FooterPages"] = GetCategory(CatePosition.Footer, seoName);
            ViewData["LeftPages"] = GetCategory(CatePosition.Left, seoName);
            var getProduct = new RepositoryResponse<Lib.ViewModels.SioProducts.ReadMvcViewModel>();

            var cacheKey = $"product_{_culture}_{seoName}";

            var data = _memoryCache.Get<Lib.ViewModels.SioProducts.ReadMvcViewModel>(cacheKey);
            if (data != null && SioService.GetConfig<bool>("IsCache"))
            {
                getProduct.IsSucceed = true;
                getProduct.Data = data;
            }
            else
            {
                Expression<Func<SioProduct, bool>> predicate;
                if (string.IsNullOrEmpty(seoName))
                {
                    predicate = p =>
                    p.Type == (int)SioPageType.Home
                    && p.Status == (int)SioContentStatus.Published && p.Specificulture == _culture;
                }
                else
                {
                    predicate = p =>
                    p.SeoName == seoName
                    && p.Status == (int)SioContentStatus.Published && p.Specificulture == _culture;
                }

                getProduct = await Lib.ViewModels.SioProducts.ReadMvcViewModel.Repository.GetSingleModelAsync(predicate);
                _memoryCache.Set(cacheKey, getProduct.Data);
                if (!SioConstants.cachedKeys.Contains(cacheKey))
                {
                    SioConstants.cachedKeys.Add(cacheKey);
                }

            }

            if (getProduct.IsSucceed)
            {
                ViewData["Title"] = getProduct.Data.SeoTitle;
                ViewData["Description"] = getProduct.Data.SeoDescription;
                ViewData["Keywords"] = getProduct.Data.SeoKeywords;
                ViewData["Image"] = getProduct.Data.ImageUrl;
                getProduct.LastUpdateConfiguration = SioService.GetConfig<DateTime?>("LastUpdateConfiguration");
                return View(getProduct.Data);
            }
            else
            {
                return Redirect($"/error/404");
            }
        }

        void GeneratePageDetailsUrls(Lib.ViewModels.SioPages.ReadMvcViewModel page)
        {
            page.DetailsUrl = GenerateDetailsUrl("Alias", new { seoName = page.SeoName });
            if (page.Articles != null)
            {
                foreach (var articleNav in page.Articles.Items)
                {
                    if (articleNav.Article != null)
                    {
                        articleNav.Article.DetailsUrl = GenerateDetailsUrl("Article", new { id = articleNav.ArticleId, seoName = articleNav.Article.SeoName });
                    }
                }
            }

            if (page.Products != null)
            {
                foreach (var productNav in page.Products.Items)
                {
                    if (productNav.Product != null)
                    {
                        productNav.Product.DetailsUrl = GenerateDetailsUrl("Product", new { seoName = productNav.Product.SeoName });
                    }
                }
            }

            if (page.Modules != null)
            {
                foreach (var nav in page.Modules)
                {
                    GeneratePageDetailsUrls(nav.Module);
                }
            }
        }

        void GeneratePageDetailsUrls(Lib.ViewModels.SioModules.ReadMvcViewModel module)
        {
            if (module.Articles != null)
            {

                foreach (var articleNav in module.Articles.Items)
                {
                    if (articleNav.Article != null)
                    {
                        articleNav.Article.DetailsUrl = GenerateDetailsUrl("Article", new { id = articleNav.ArticleId, seoName = articleNav.Article.SeoName });
                    }
                }
            }
        }

        string GenerateDetailsUrl(string type, object routeValues)
        {
            return SioCmsHelper.GetRouterUrl(type, routeValues, Request, Url);
        }

        #endregion
        List<Lib.ViewModels.SioPages.ReadListItemViewModel> GetCategory(SioEnums.CatePosition position, string seoName)
        {
            var result = new List<Lib.ViewModels.SioPages.ReadListItemViewModel>();
            var cacheKey = $"page_position_{position}";

            var data = _memoryCache.Get<List<Lib.ViewModels.SioPages.ReadListItemViewModel>>(cacheKey);
            if (data != null && SioService.GetConfig<bool>("IsCache"))
            {
                result = data;
            }
            else
            {
                var getTopCates = Lib.ViewModels.SioPages.ReadListItemViewModel.Repository.GetModelListBy
            (c => c.Specificulture == _culture && c.SioPagePosition.Any(
              p => p.PositionId == (int)position)
            );

                result = getTopCates.Data ?? new List<Lib.ViewModels.SioPages.ReadListItemViewModel>();
                foreach (var cate in result)
                {
                    switch (cate.Type)
                    {
                        case SioPageType.Blank:
                            foreach (var child in cate.Childs)
                            {
                                child.Page.DetailsUrl = GenerateDetailsUrl("Page", new { seoName = child.Page.SeoName });
                            }
                            break;

                        case SioPageType.StaticUrl:
                            cate.DetailsUrl = cate.StaticUrl;
                            break;

                        case SioPageType.Home:
                        case SioPageType.ListArticle:
                        case SioPageType.Article:
                        case SioPageType.Modules:
                        default:
                            cate.DetailsUrl = GenerateDetailsUrl("Page", new { seoName = cate.SeoName });
                            break;
                    }
                }

            }

            foreach (var cate in result)
            {
                cate.IsActived = (cate.SeoName == seoName
                    || (cate.Type == SioPageType.Home && string.IsNullOrEmpty(seoName)));
                cate.Childs.ForEach((Action<Lib.ViewModels.SioPagePages.ReadViewModel>)(c =>
                {
                    c.IsActived = (
                    c.Page.SeoName == seoName);
                    cate.IsActived = cate.IsActived || c.IsActived;
                }));
            }
            return result;
        }

        [ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
        public IActionResult Error()
        {
            return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
        }
    }
}
